﻿using System;
using System.Collections.Generic;
using System.IO;
using Castle.DynamicProxy;
using Framework.Core.Reflection;

namespace Framework.Core.Recorder
{
    /// <summary>
    /// TODO : BECAREFULL of serialization for Snapshot and supplied serialization serialize result from supplied serialization
    /// TODO : See Windsor for caching in order to avoid serialization during recordKey generation
    /// TODO : defensive make test on unserializable return value or parameter 
    /// </summary>

    public sealed class HardMock : IHardMock
    {
        private static readonly ProxyGenerator ProxyGenerator = new ProxyGenerator();

        private readonly IEnumerable<Type> excludedTypes;

        public HardMock(params Type[] excludedTypes)
        {
            this.excludedTypes = excludedTypes;
        }

        internal T BuildRecorderOver<T>(T target, ICallKeyBuilder callKeyBuilder) where T : class
        {
            Preconditions<T>();

            return ProxyGenerator.CreateInterfaceProxyWithTarget(target,
                new DependencyRecorder(
                    new DependencyRepository(new BinarySerializer()),
                    callKeyBuilder,
                    new FilteredMethodFactory(new MethodFactory(), excludedTypes)));
        }

        private static void Preconditions<T>() where T : class
        {
            if (!typeof(T).IsInterface)
            {
                throw new HardMockException("type should be an interface");
            }

            if (!typeof(T).IsVisible)
            {
                throw new HardMockException("type should be public");
            }
        }

        public T BuildRecorderOver<T>(T target)
            where T : class
        {
            return BuildRecorderOver(target, new PropertyCallKeyBuilder(new CallKeyBuilder()));
        }

        internal T BuildMockFrom<T>(Stream stream, ICallKeyBuilder callKeyBuilder) where T : class
        {
            return
                ProxyGenerator.CreateInterfaceProxyWithoutTarget<T>(
                    new DependencyReplayer(
                        new DependencyRepository(new BinarySerializer(), stream),
                        callKeyBuilder,
                        new FilteredMethodFactory(new MethodFactory(), excludedTypes)));
        }

        public T BuildMockFrom<T>(Stream stream) where T : class
        {
            return BuildMockFrom<T>(stream, new PropertyCallKeyBuilder(new CallKeyBuilder()));
        }

    }
}